package yxgf.oem.oemquotemgt.plugin.form;

import kd.bos.dataentity.entity.DynamicObject;
import kd.bos.dataentity.entity.DynamicObjectCollection;
import kd.bos.entity.datamodel.events.ChangeData;
import kd.bos.entity.datamodel.events.PropertyChangedArgs;
import kd.bos.form.plugin.AbstractFormPlugin;
import kd.bos.openapi.common.result.CustomApiResult;
import kd.bos.orm.query.QCP;
import kd.bos.orm.query.QFilter;
import kd.bos.servicehelper.BusinessDataServiceHelper;
import kd.bos.servicehelper.DispatchServiceHelper;
import kd.bos.servicehelper.QueryServiceHelper;
import yxgf.oem.oempricemgt.commons.dto.InvPriceDto;

import javax.swing.text.html.Option;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.time.ZoneId;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @description： 代工配方定价单插件
 * @version: v1.0
 * @author: 胡欢
 * @date: 2025/5/27
 */
public class RecipePricingFormPlugIn extends AbstractFormPlugin {
    @Override
    public void afterBindData(EventObject e) {
        super.afterBindData(e);
        //库存价类型空白时根据当前日期自动选择类型
        EventObject stockPriceType = (EventObject) this.getModel().getValue("yxgf_combofield1");
        if (Objects.isNull(stockPriceType)) {
            if (LocalDate.now().getDayOfMonth() <= 15) {
                this.getModel().setValue("yxgf_combofield1", "BYDKCJ");
            } else {
                this.getModel().setValue("yxgf_combofield1", "XYDKCJ");
            }
            this.getView().updateView("yxgf_combofield1");
        }

    }

    @Override
    public void propertyChanged(PropertyChangedArgs e) {
        super.propertyChanged(e);
        String filedName = e.getProperty().getName();
        ChangeData[] changeSet = e.getChangeSet();
        //监听销售组织 同步更新 订单提货点、原料库存价来源组织、产品实际成本组织
        if ("yxgf_sale_org".equals(filedName)) {
            DynamicObject newValue = (DynamicObject) changeSet[0].getNewValue();
            if (Objects.nonNull(newValue)) {
                this.changeOrg(newValue.getLong("id"));
            }
        }

        //监听基数计算方式-第三方原料
        if ("yxgf_material_code".equals(filedName)) {
            for (ChangeData changeData : changeSet) {
                Optional<DynamicObject> dataEntity = Optional.ofNullable(changeData.getDataEntity());
                dataEntity.ifPresent(this::countBaseNumMt);
            }
        }

        //监听配方组成-原料
        if ("yxgf_basedatafield3".equals(filedName)) {
            for (ChangeData changeData : changeSet) {
                //获取新增原料
                Optional<DynamicObject> newRow = Optional.ofNullable((DynamicObject) changeData.getNewValue());
                newRow.ifPresent(this::synMaterialPrice);
            }
        }

        //监听配方组成-使用量
        if ("yxgf_use_num".equals(filedName)) {
            for (ChangeData changeData : changeSet) {
                Optional<DynamicObject> dataEntity = Optional.ofNullable(changeData.getDataEntity());
                if (dataEntity.isPresent()) {
                    DynamicObject parentRow = (DynamicObject) dataEntity.get().getParent();
                    this.countProductUsage(parentRow);
                }
            }
        }

        //监听原料价格明细-原料定价
        if ("yxgf_mat_price".equals(filedName)) {
            DynamicObjectCollection productDet = this.getModel().getDataEntity(true).getDynamicObjectCollection("yxgf_entryentity");
            for (DynamicObject row : productDet) {
                this.countProductUsage(row);
            }
        }

        //监听原料价格明细-原料编码
        if ("yxgf_basedatafield".equals(filedName)) {
            for (ChangeData changeData : changeSet) {
                Optional<DynamicObject> dataEntity = Optional.ofNullable(changeData.getDataEntity());
                dataEntity.ifPresent(this::setMaterialRefPrice);
            }
        }

    }

    //更新原料价格明细行参考价格数据（配方组成行，物料Id）
    private void setMaterialRefPrice(DynamicObject mtPriceRow) {
        DynamicObject data = this.getModel().getDataEntity(true);
        String stockPriceType = data.getString("yxgf_combofield1");
        Optional<DynamicObject> matterial = Optional.ofNullable(mtPriceRow.getDynamicObject("yxgf_basedatafield"));
        Optional<DynamicObject> saleOrg = Optional.ofNullable(data.getDynamicObject("yxgf_sale_org"));
        Optional<DynamicObject> stockOrg = Optional.ofNullable(data.getDynamicObject("yxgf_oth_addr"));
        Optional<DynamicObject> customer = Optional.ofNullable(data.getDynamicObject("yxgf_customer"));

        if (!matterial.isPresent() || !saleOrg.isPresent() || !stockOrg.isPresent() || !customer.isPresent()) {
            this.getView().showMessage("请先补充【销售组织】、【原料库存价来源组织】、【客户信息】！");
            return;
        }

        if (!matterial.isPresent()) return;
        Long matterialId = matterial.get().getLong("id");
        int rowSeq = mtPriceRow.getInt("seq");
        //采购预测市场价（库存组织Id，原料id）
        CustomApiResult<BigDecimal> purchasemarketPriceResult = DispatchServiceHelper.invokeService("yxgf.oem.oempricemgt.mservice.factory",
                "yxgf_oempricemgt", "IGetPriceService", "obtainLatestFCPriceMt", saleOrg.get().getLong("id"), matterialId);
        mtPriceRow.set("yxgf_mark_price", purchasemarketPriceResult.isStatus() ? purchasemarketPriceResult.getData() : 0);
//        this.getModel().setValue("yxgf_mark_price", purchasemarketPriceResult.isStatus() ? purchasemarketPriceResult.getData() : 0, rowSeq);

        //采购库存价(库存价类型、库存组织Id、原料id)
        CustomApiResult<BigDecimal> purchaseStockPriceResult = DispatchServiceHelper.invokeService("yxgf.oem.oempricemgt.mservice.factory",
                "yxgf_oempricemgt", "IGetPriceService", "obtainLatestKCPrice", stockPriceType, stockOrg.get().getLong("id"), matterialId);
        mtPriceRow.set("fk_yxgf_stock_price", purchaseStockPriceResult.isStatus() ? purchaseStockPriceResult.getData() : 0);
//        this.getModel().setValue("fk_yxgf_stock_price", purchaseStockPriceResult.isStatus() ? purchaseStockPriceResult.getData() : 0, rowSeq);

        //原料友商价格（销售组织，原料id）
//        CustomApiResult<BigDecimal> matterialYSPriceResult = DispatchServiceHelper.invokeService("yxgf.oem.oempricemgt.mservice.factory", "yxgf_oempricemgt",
//                "IGetPriceService", "obtainLatestCompetitorPrices", customer.get().getLong("id"), matterial.get().getLong("id"));
//        this.getModel().setValue("fk_yxgf_competitor_price", matterialYSPriceResult.isStatus() ? matterialYSPriceResult.getData() : 0, rowSeq);

        //财务原料均价（库存组织Id，原料Id）
        CustomApiResult<List<InvPriceDto>> financeMatterialPrice = DispatchServiceHelper.invokeService("yxgf.oem.oempricemgt.mservice.factory",
                "yxgf_oempricemgt", "IGetPriceService", "obtainLatestInventoryPrice", matterialId, stockOrg.get().getLong("id"));
        if (financeMatterialPrice.isStatus()) {
            StringBuilder priceStr = new StringBuilder();
            financeMatterialPrice.getData().forEach(item -> priceStr.append(item.getInventoryName()).append(":").append(item.getPrice().setScale(2, RoundingMode.HALF_UP)).append("\n"));
//            this.getModel().setValue("fk_yxgf_stock_price", purchaseStockPriceResult.isStatus() ? purchaseStockPriceResult.getData() : 0, rowSeq);
            mtPriceRow.set("yxgf_cwyljj", priceStr);
        }

        this.getView().updateView("yxgf_entryentity1");
    }

    //计算产品明细配方成本（产品明细行）
    private void countProductUsage(DynamicObject parentRow) {
        DynamicObjectCollection subRows = parentRow.getDynamicObjectCollection("yxgf_subentryentity1");
        HashMap<Long, BigDecimal> mtUsageMap = this.countRecipeMtUsage(parentRow);
        if (Objects.nonNull(mtUsageMap)) {
            //计算营养项目占比
            this.setMtNutritionDet(mtUsageMap, parentRow);
            //计算配方成本
            HashMap<Long, BigDecimal> mtPriceMap = this.getMaterialPrice();
            BigDecimal cost = new BigDecimal(0);
            for (DynamicObject subRow : subRows) {
                Long mtId = subRow.getDynamicObject("yxgf_basedatafield3").getLong("id");
                if (Objects.isNull(mtPriceMap.get(mtId)) || Objects.isNull(mtUsageMap.get(mtId))) return;
                BigDecimal temp = mtPriceMap.get(mtId).multiply(mtUsageMap.get(mtId));

                if (temp.equals(BigDecimal.ZERO)) return;
                cost = cost.add(temp);
            }
            this.getModel().setValue("yxgf_formula_amount", cost, parentRow.getInt("seq") - 1);
        } else {
            this.getModel().setValue("yxgf_formula_amount", 0L, parentRow.getInt("seq") - 1);
        }

    }

    //计算配方使用量（产品明细行）
    private HashMap<Long, BigDecimal> countRecipeMtUsage(DynamicObject parentRow) {
        DynamicObjectCollection subRows = parentRow.getDynamicObjectCollection("yxgf_subentryentity1");
        BigDecimal usageTotal = BigDecimal.ZERO;
        HashMap<Long, BigDecimal> mtUsageMap = new HashMap<>();
        for (DynamicObject subRow : subRows) {
            BigDecimal mtUsage = subRow.getBigDecimal("yxgf_use_num");
            if (mtUsage.compareTo(new BigDecimal("0")) == 0) {
//                this.getView().showMessage("请录入【配方组成】原料使用量！");
                this.getModel().setValue("yxgf_formula_amount", 0L, parentRow.getInt("seq") - 1);
                return null;
            }
            usageTotal = mtUsage.add(usageTotal);
            Optional<DynamicObject> mt = Optional.ofNullable(subRow.getDynamicObject("yxgf_basedatafield3"));
            if (!mt.isPresent()) {
                return null;
            }
            mtUsageMap.put(mt.get().getLong("id"), mtUsage);
        }
        return usageTotal.compareTo(new BigDecimal("1000")) == 0 ? mtUsageMap : null;
    }

    //批量更新营养项目单据体
    private void setMtNutritionDet(HashMap<Long, BigDecimal> mtUsageMap, DynamicObject productRow) {
        DynamicObject[] materials = BusinessDataServiceHelper.load("bd_material", "" + "id," + "yxgf_nutrition," + "yxgf_levels_bl", new QFilter("id", QCP.in, mtUsageMap.keySet().toArray()).toArray());

        HashMap<Long, DynamicObject> nutritionIdAndDyMap = new HashMap<>();
        HashMap<Long, BigDecimal> nutritionIdAndContentMap = new HashMap<>();

        //遍历物料明细
        for (DynamicObject material : materials) {
            Long materialId = material.getLong("id");
            BigDecimal usage = mtUsageMap.get(materialId);
            if (usage == null) continue;

            //遍历物料 营养项目明细
            material.getDynamicObjectCollection("yxgf_trophicentry").forEach(n -> {
                Long nutritionId = n.getDynamicObject("yxgf_nutrition").getLong("id");
                BigDecimal content = n.getBigDecimal("yxgf_levels_bl");
                BigDecimal prop = usage.multiply(content);

                nutritionIdAndDyMap.computeIfAbsent(nutritionId, k -> n.getDynamicObject("yxgf_nutrition"));

                nutritionIdAndContentMap.merge(nutritionId, prop, BigDecimal::add);
            });
        }

        //获取产品营养占比明细
        DynamicObjectCollection nutritionSubDet = productRow.getDynamicObjectCollection("yxgf_subentryentity11");
        nutritionSubDet.clear();
        for (Long id : nutritionIdAndDyMap.keySet()) {
            DynamicObject row = nutritionSubDet.addNew();
            row.set("yxgf_material_item", nutritionIdAndDyMap.get(id));
            row.set("yxgf_proportion", nutritionIdAndContentMap.get(id).divide(new BigDecimal("1000")));
        }

        this.getView().updateView("yxgf_subentryentity11");
    }

    //获取原料价格明细 原料-定价
    private HashMap<Long, BigDecimal> getMaterialPrice() {
        HashMap<Long, BigDecimal> priceMap = new HashMap<>();
        this.getModel().getDataEntity(true).getDynamicObjectCollection("yxgf_entryentity1").stream().forEach(price -> priceMap.put(price.getDynamicObject("yxgf_basedatafield").getLong("id"), price.getBigDecimal("yxgf_mat_price")));
        return priceMap;
    }

    //原料价格明细新增行(新增原料)
    private void synMaterialPrice(DynamicObject newVal) {
        DynamicObjectCollection mtPriceDet = this.getModel().getDataEntity(true).getDynamicObjectCollection("yxgf_entryentity1");
        //原料价格明细行遍历
        for (DynamicObject item : mtPriceDet) {
            Optional<DynamicObject> mt = Optional.ofNullable(item.getDynamicObject("yxgf_basedatafield"));
            //清空无原料行
            if (mt.equals(Optional.empty())) {
                mtPriceDet.remove(item);
                continue;
            }

            Long itemId = mt.get().getLong("id");
            Long newMtId = newVal.getLong("id");
            //存在重复原料，跳过
            if (newMtId.equals(itemId)) {
                continue;
            }
        }
        DynamicObject mtPriceRow = mtPriceDet.addNew();
        mtPriceRow.set("yxgf_basedatafield", newVal);
        this.setMaterialRefPrice(mtPriceRow);
        this.getView().updateView("yxgf_entryentity1");

    }

    //选择销售组织赋值组织设置
    private void changeOrg(Long orgId) {
        this.getModel().setValue("yxgf_delivery_addr", orgId);
        this.getModel().setValue("yxgf_oth_addr", orgId);
        //多选基础资料类型特殊处理
        DynamicObjectCollection stockPriceOrg = this.getModel().getDataEntity(true).getDynamicObjectCollection("yxgf_stock_price_org");
        stockPriceOrg.clear();
        DynamicObject data = BusinessDataServiceHelper.loadSingle(orgId, "bos_org");
        stockPriceOrg.addNew().set("fbasedataid", data);
        this.getView().updateView("yxgf_stock_price_org");
    }

    //处理基数计算方式单据体变动行
    private void countBaseNumMt(DynamicObject row1) {

        DynamicObject row = this.getModel().getDataEntity(true).getDynamicObjectCollection("base_compute").get(row1.getInt("seq") - 1);
        Optional<Long> mtId = Optional.ofNullable(row.getDynamicObject("yxgf_material_code")).map(d -> d.getLong("id"));
        //判断是否填入第三方原料
        if (mtId.isPresent()) {
            //获取基数计算日期、报价基数计算日期
            Integer advDays = (Integer) this.getModel().getValue("yxgf_quote_days");
            Date quetoDate = (Date) this.getModel().getValue("yxgf_price_base_date");

            if (advDays.equals(0) || Objects.isNull(quetoDate)) {
                row.set("yxgf_material_code", null);
                this.getView().showMessage("请先填写报价基数计算天数与报价基数计算日期");
                return;
            }
            //生成区间日期数组
            List<Date> datesBetween = this.getDatesBetween(quetoDate, advDays);
            //计算渠道均价
            DynamicObjectCollection thirdMtPrice = this.getThirdMtPrice(datesBetween, mtId.get());
            if (thirdMtPrice.size() == 0) {
                this.getView().showMessage("系统中无该原料在基数计算日期期间内的价格！");
            }
            BigDecimal tpriceTotal = new BigDecimal(0);
            for (DynamicObject tp : thirdMtPrice) {
                BigDecimal price = tp.getBigDecimal("price");
                tpriceTotal = tpriceTotal.add(price);
            }
            row.set("yxgf_avg_price", tpriceTotal.divide(BigDecimal.valueOf(thirdMtPrice.size()), 2, RoundingMode.HALF_UP));
            BigDecimal weight = row.getBigDecimal("yxgf_weight");
            if (weight.compareTo(new BigDecimal("0")) != 0) {
                row.set("yxgf_subtotal", weight.multiply(tpriceTotal));
            }
            //获取第三方渠道价格明细子单据体实体
            DynamicObjectCollection subDet = row.getDynamicObjectCollection("yxgf_subentryentity");
            subDet.clear();
            DynamicObject mtBasedata = BusinessDataServiceHelper.loadSingle(mtId.get(), "yxgf_cha_material");
            for (Date date : datesBetween) {
                DynamicObject subRow = subDet.addNew();
                subRow.set("yxgf_date", date);
                subRow.set("yxgf_mat_code", mtBasedata);
                for (DynamicObject price : thirdMtPrice) {
                    if (date.equals(price.getDate("bizDate"))) {
                        subRow.set("yxgf_hyw_price", price.getBigDecimal("price"));
                        break;
                    }
                }
            }
            this.getView().updateView("base_compute");
            this.getView().updateView("yxgf_subentryentity");
            this.getView().updateView("base_compute");
        }
    }

    //获取第三方价格区间价格
    private DynamicObjectCollection getThirdMtPrice(List<Date> dates, Long mtId) {
        QFilter dateQF = new QFilter("yxgf_bizdate", QCP.in, dates);
//        QFilter endDateQF = new QFilter("yxgf_bizdate", QCP.less_equals, endDate);
        QFilter mtIdQF = new QFilter("yfgf_price_detail.yxgf_mt", QCP.equals, mtId);
        QFilter enableQF = new QFilter("enable", QCP.equals, "1");
        QFilter[] qFilters = {dateQF, mtIdQF, enableQF};

        return QueryServiceHelper.query("yxgf_material_price", "" + "yxgf_bizdate as bizDate," + "yfgf_price_detail.yxgf_mt as mt," + "yfgf_price_detail.yxgf_third_party_price as price", qFilters);
    }

    //生成从startDate到endDate的所有日期
    private List<Date> getDatesBetween(Date quetoDate, Integer advDays) {
        LocalDate endDate = quetoDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
        LocalDate startDate = endDate.minusDays(advDays);
        long daysBetween = ChronoUnit.DAYS.between(startDate, endDate);
        return Stream.iterate(endDate, date -> date.minusDays(1)).limit(daysBetween).map(date -> Date.from(date.atStartOfDay(ZoneId.systemDefault()).toInstant())).collect(Collectors.toList());
    }


}


